package com.docker.test.netty.server;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import com.corundumstudio.socketio.listener.ExceptionListenerAdapter;
import com.docker.test.netty.Dao.Chat;
import com.docker.test.netty.Dao.ClientInfo;
import com.docker.test.netty.Dao.MessageInfo;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class NettyServer implements ApplicationListener<ContextRefreshedEvent> {
    private static Logger logger = LoggerFactory.getLogger(NettyServer.class);
    @Value("${netty_ip}")
    private String netty_ip;
    @Value("${netty_port}")
    private String netty_port;

    //会话集合
    private static final ConcurrentSkipListMap<String, ClientInfo> webSocketMap = new ConcurrentSkipListMap<>();
    //计数器，记录当前链接数
    private static AtomicInteger onlineCount = new AtomicInteger(0);
    private SocketIOServer server;


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        //端口
        int port = Integer.parseInt(netty_port);
        //服务器ip
        String ip = netty_ip;

        //避免重复启动

        if(server == null){
            Configuration config = new Configuration();
            config.setHostname(ip);
            config.setPort(port);
            //身份验证
            config.setAuthorizationListener(handshakeData -> {
                //http://localhost:8081?username=test&password=test
                //例如果使用上面的链接进行connect，可以使用如下代码获取用户密码信息
                //String username = data.getSingleUrlParam("username");
                //String password = data.getSingleUrlParam("password");
                return true;
            });

            config.setExceptionListener(new ExceptionListenerAdapter() {
                @Override
                public boolean exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {

                    logger.error(e.getMessage());
                    ctx.close();
                    return true;
                }
            });

            //创建服务器
            server = new SocketIOServer(config);

            //添加链接事件监听

            server.addConnectListener(new ConnectListener() {
                @Override
                public void onConnect(SocketIOClient socketIOClient) {
                    String clientId = socketIOClient.getHandshakeData().getSingleUrlParam("clientid");
                    logger.info("web socket connected and clent id :【{}】",clientId);
                    UUID session = socketIOClient.getSessionId();
                    ClientInfo ui = webSocketMap.get(clientId);
                    if(ui == null){
                        ui = new ClientInfo();
                        ui.setClientId(clientId);
                        ui.setMostSignificantBits(session.getMostSignificantBits());
                        ui.setLeastSignificantBits(session.getLeastSignificantBits());
                        ui.setOnline(true);
                        webSocketMap.put(clientId,ui);
                        //在线数增加
                        logger.info("new socket connection sessionid :【{}】,currernt connect num:【{}】",clientId,onlineCount.incrementAndGet());
                    }
                }
            });

            //添加销毁链接事件监听
            server.addDisconnectListener(new DisconnectListener() {
                @Override
                public void onDisconnect(SocketIOClient socketIOClient) {
                    String clientId = socketIOClient.getHandshakeData().getSingleUrlParam("clientid");
                    webSocketMap.remove(clientId);
                    //在线数减少
                    logger.info("new socket disconnection sessionid :【{}】,currernt connect num:【{}】",clientId,onlineCount.decrementAndGet());

                }
            });

            //添加消息监听事件
            server.addEventListener("message_event", MessageInfo.class, new DataListener<MessageInfo>() {
                @Override
                public void onData(SocketIOClient socketIOClient, MessageInfo messageInfo, AckRequest ackRequest) throws Exception {
                    SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                    String time = simpleDateFormat.format(new Date());
                    Chat chat  = new Chat();
                    chat.setUserSendId(messageInfo.getTargetClientId());
                    chat.setUserReceiveId(messageInfo.getSourceClientId());
                    chat.setContent(messageInfo.getMsg());
                    chat.setCreatetime(time);
                    // TODO: 2021/5/13  保存聊天记录
                    String targetClientId = messageInfo.getTargetClientId();
                    ClientInfo clientInfo = webSocketMap.get(targetClientId);
                    if (clientInfo != null && clientInfo.isOnline()){
//                        logger.info("send message:【{}】",messageInfo.getMsg());
                        UUID target = new UUID(clientInfo.getMostSignificantBits(),clientInfo.getLeastSignificantBits());
//                        logger.info("target connect:【{}】",target);
                        MessageInfo sendData = new MessageInfo();
                        sendData.setSourceClientId(messageInfo.getSourceClientId());
                        sendData.setTargetClientId(messageInfo.getTargetClientId());
                        sendData.setMsg(messageInfo.getMsg());
                        //向当前会话发送消息
//                        socketIOClient.sendEvent("message_event",sendData);
                        //向目标会话发送消息
//                        server.getClient(target).sendEvent("message_event",sendData);
                        SocketIOClient socketIOClient1 = server.getClient(target);
                        server.getClient(target).sendEvent("message_event",sendData);
                    }
                }
            });

//            server.addEventListener("message_event", String.class, new DataListener<String>() {
//                @Override
//                public void onData(SocketIOClient socketIOClient, String s, AckRequest ackRequest) throws Exception {
//                    logger.info("messadge:【{}】",s);
//                }
//            });

            //需要执行该代码，启动服务器
            server.start();
            logger.info("server running");
        }
    }
}
